#include "mainwindow.h"
#include "ui_mainwindow.h"

#include <QMessageBox>
#include "math.h"
#include "omp.h"
#include "windows.h"
#include <QProgressDialog>
#include <QShortcut>

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    connect(ui->spinBox_4,SIGNAL(valueChanged(int)),this,SLOT(updateEstimate()));
    connect(ui->spinBox_3,SIGNAL(valueChanged(int)),this,SLOT(updateEstimate()));
    connect(ui->spinBox_2,SIGNAL(valueChanged(int)),this,SLOT(updateEstimate()));
    updateEstimate();

    table = new QTableWidget(0);
    splineTable = new QTableWidget(0);
    ui->label_10->setPixmap(QPixmap(":/new/task.png"));

    isMagic = true;
    changeMagicBehavior();
    new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_Q), this, SLOT(changeMagicBehavior()));

#if defined(_OPENMP)
   //printf("Compiled by an OpenMP-compliant implementation.\n");
   QMessageBox msgBox;
   msgBox.setText(QString("omp_get_num_threads %1").arg(omp_get_num_threads()));
   //msgBox.exec();
   //printf("The result of omp_get_num_threads %i\n", omp_get_num_threads());
#endif

}

MainWindow::~MainWindow()
{
    delete table;
    delete splineTable;
    delete ui;
}

bool MainWindow::event(QEvent *mEvent)
{
    if (mEvent->type()==QEvent::Close)
    {
        table->close();
        splineTable->close();
        this->close();
        return true;
    }
    return QMainWindow::event(mEvent);
}


double u(double x, double y)
{
    return exp(1-x*x-y*y);
}

void setBorderAndF (double**x, double**f, int n, int m, int variant)
{
    if (variant==3)
    {
        double h = 2./n;
        double k = 2./m;
        double a = -1.0;
        double c = -1.0;
        for (int i=0; i<n+1; i++)
        {
            x[i][m] = x[i][0] = 1 - (a+i*h)*(a+i*h);
        }
        for (int j=0; j<m+1; j++)
        {
            x[0][j] = 1 - (c+j*k)*(c+j*k);
            x[n][j] = x[0][j] * exp((c+j*k));
        }

        for (int i=0; i<n+1; i++)
            for (int j=0; j<m+1; j++)
            {
                f[i][j] = fabs((c+j*k)*(c+j*k) - (a+i*h)*(a+i*h));
            }
    }
    else if (variant==2)
    {
        double h = 2./n;
        double k = 2./m;
        double a = -1.0;
        double c = -1.0;
        for (int i=0; i<n+1; i++)
        {
            x[i][m] = x[i][0] = fabs(sin( M_PI*(a+i*h)));
        }
        for (int j=0; j<m+1; j++)
        {
            x[n][j] = x[0][j] = 1 - (c+j*k)*(c+j*k);
        }

        for (int i=0; i<n+1; i++)
            for (int j=0; j<m+1; j++)
            {
                f[i][j] = fabs(pow(sin(M_PI*(c+j*k)*(a+i*h)),3));
            }
    }
    else if (variant==-1) // test
    {
        double h = 2./n;
        double k = 2./m;
        double a = -1.0;
        double b = 1.0;
        double c = -1.0;
        double d = 1.0;
        for (int i=0; i<n+1; i++)
        {
            x[i][0] = u(a+i*h,c);//exp(1 - (a+i*h)*(a+i*h)-c*c);
            x[i][m] = u(a+i*h,d);//exp(1 - (a+i*h)*(a+i*h)-d*d);
        }
        for (int j=0; j<m+1; j++)
        {
            x[0][j] = u(a,c+j*k);//exp(1 - (c+j*k)*(c+j*k)-a*a);
            x[n][j] = u(b,c+j*k);//exp(1 - (c+j*k)*(c+j*k)-b*b);
        }

        for (int i=0; i<n+1; i++)
            for (int j=0; j<m+1; j++)
            {
                double z = 1 - (c+j*k)*(c+j*k) - (a+i*h)*(a+i*h);
                f[i][j] = 4.0*exp(z)*z;
            }
    }
    else if (variant==-2) //Green LR
    {
        double h = 2./n;
        double k = 2./m;
        double a = -1.0;
        double c = -1.0;
        for (int i=0; i<n+1; i++)
        {
            x[i][m] = x[i][0] = (1 - (a+i*h)*(a+i*h)-c*c);
        }
        for (int j=0; j<m+1; j++)
        {
            x[n][j] = x[0][j] = (1 - (c+j*k)*(c+j*k)-a*a);
        }

        for (int i=0; i<n+1; i++)
            for (int j=0; j<m+1; j++)
            {
                f[i][j] = -4;
            }
    }
}

void setInitial(double**x, int n, int m, int type)
{
    if (type==0) //Zero
    {
        for (int i=0; i<n+1; i++)
            memset(x[i],0,(m+1)*sizeof(double));
    }
    else if (type==1) //Average
    {
        double h = 2./n;
        double k = 2./m;
        double a = -1.0;
        double b = 1.0;
        double c = -1.0;
        double d = 1.0;
        for (int i=1; i<n; i++)
            for (int j=1; j<m; j++)
            {
                double y1 = x[0][j];
                double y2 = x[n][j];
                double x1 = a;
                double x2 = b;
                double x0 = a + i*h;
                double xInter = (y2-y1)/(x2-x1)*x0 - (x1*y2-x2*y1)/(x2-x1);

                y1 = x[i][0];
                y2 = x[i][m];
                x1 = c;
                x2 = d;
                x0 = c + j*k;
                double yInter = (y2-y1)/(x2-x1)*x0 - (x1*y2-x2*y1)/(x2-x1);
                x[i][j] = (xInter+yInter)/2.0;
            }
    }
    else if (type==2) //Exact for test
    {
        double h = 2./n;
        double k = 2./m;
        double a = -1.0;
        //double b = 1.0;
        double c = -1.0;
        //double d = 1.0;
        for (int i=1; i<n; i++)
            for (int j=1; j<m; j++)
            {
                x[i][j] = u(a+i*h,c+j*k);
            }
    }
}


Pair countResidual(double**x1,double**f, int n, int m)
{
    double invhsq = (double)(n*n)/4.0; // 1/h^2
    double invksq = (double)(m*m)/4.0;
    //Residual norm:
    double res = -1;
    double residual=0;
    double sum = 0;
    for (int i=1; i<n; i++)
    {
        for (int j=1; j<m; j++)
        {
            residual = x1[i+1][j]*invhsq +
                             x1[i-1][j]*invhsq  -
                             x1[i][j]*2*(invhsq+invksq)  +
                             x1[i][j-1]*invksq  +
                             x1[i][j+1]*invksq  + f[i][j];
            if (fabs(residual)>res)
                res=fabs(residual);
            sum+=residual*residual;
        }
    }
    sum = sqrt(sum);
    return Pair(res,-1, sum);
}

Pair MainWindow::computeNext(double**x0, double** x1, double**f, int n, int m, int type)
{
//    LARGE_INTEGER freq;
//    LARGE_INTEGER sQP, fQP;
//    QueryPerformanceFrequency(&freq);
//    QueryPerformanceCounter(&sQP);

    const double invhsq = (double)(n*n)/4.0; // 1/h^2
    const double invksq = (double)(m*m)/4.0;

    for (int j=0; j<=m; j++)
    {
        x1[0][j] = x0[0][j];
        x1[n][j] = x0[0][j];
    }
    for (int i=0; i<=n; i++)
    {
        x1[i][0] = x0[i][0];
        x1[i][m] = x0[0][m];
    }

    if (type==0) // Jacobi
    {
#pragma omp parallel for
        for (int i=1; i<n; i++) //Jacobi
        {
            for (int j=1; j<m; j++)
            {
                x1[i][j] = x0[i+1][j]*invhsq +
                           x0[i-1][j]*invhsq  +
                           x0[i][j-1]*invksq  +
                           x0[i][j+1]*invksq  + f[i][j];
                x1[i][j]/= 2.0*(invhsq+invksq);
            }
        }
    }
    else if (type==1) //Zeidel
    {
//#pragma omp parallel for
        for (int i=1; i<n; i++) //Zeidel
        {
            for (int j=1; j<m; j++)
            {
                x1[i][j] = x0[i+1][j]*invhsq +
                           x1[i-1][j]*invhsq  +
                           x1[i][j-1]*invksq  +
                           x0[i][j+1]*invksq  + f[i][j];
                x1[i][j]/= 2.0*(invhsq+invksq);
            }
        }
    }

//    QueryPerformanceCounter(&fQP);
//    if (true)
//    {
//        FILE* aaa;
//        QString z = "timings_2";
//        z+=".csv";
//        aaa=fopen(z.toStdString().c_str(), "a");
//        fprintf(aaa,"%lf\n",(fQP.QuadPart-sQP.QuadPart)/(double)freq.QuadPart);
//        fclose(aaa);
//    }
    return countResidual(x1,f,n,m);
}


double normRazn (double** x0, double** x1, int n, int m)
{
    double res = 0.0;
    for (int i=1; i<n; i++)
        for (int j=1; j<m; j++)
            if (fabs(x0[i][j]-x1[i][j]) > res)
                res = fabs(x0[i][j]-x1[i][j]);
    return res;
}

double MainWindow::maxFourthDerivative (double** f, int n, int m, double &xDer, double& yDer, int multiplier)
{
    if (multiplier<0)
        multiplier = ui->spinBox_5->value();
    double tempX, tempY;
    double x=-1.0,y=-1.0;
    double h = 2.0/n*multiplier;
    double k = 2.0/m*multiplier;
    for (int i=2*multiplier; i<=n-2*multiplier; i+=multiplier)
        for (int j=2*multiplier; j<=m-2*multiplier; j+=multiplier)
        {
            tempX = f[i-2*multiplier][j] - 4*f[i-multiplier][j] + 6*f[i][j] - 4*f[i+multiplier][j] + f[i+2*multiplier][j];
            tempX/=h*h*h*h;
            tempY = f[i][j-2*multiplier] - 4*f[i][j-1*multiplier] + 6*f[i][j] - 4*f[i][j+1*multiplier] + f[i][j+2*multiplier];
            tempY/=k*k*k*k;
            if (fabs(tempX)>x)
                x=fabs(tempX);
            if (fabs(tempY)>y)
                y=fabs(tempY);
        }
    xDer = x;
    yDer = y;
    return x>y ? x : y;
}

void MainWindow::on_pushButton_3_clicked()
{
    //Main task
    int variant = ui->spinBox->value();
    int n = ui->spinBox_2->value();
    int m = ui->spinBox_3->value();
    double h = 2.0/n;
    double k = 2.0/m;
    double a=-1,c=-1;
    //double b=1,d=1;
    int initial = -1;
    if (ui->radioButton->isChecked())
        initial = 0;
    else if (ui->radioButton_2->isChecked())
        initial = 1;
    else if (ui->radioButton_5->isChecked())
        initial = 2;
    int type = ui->radioButton_3->isChecked() ? 0 : 1;

    double** x0, **x1;
    x0 = new double*[n+1];
    x1 = new double*[n+1];
    double** f = new double*[n+1];
    for (int i=0; i<n+1; i++)
    {
        x0[i] = new double[m+1];
        x1[i] = new double[m+1];
        f[i] = new double[m+1];
    }

    setBorderAndF(x0,f, n,m,variant);
    setBorderAndF(x1,f,n,m,variant);
    setInitial(x0,n,m,initial);
    setInitial(x1,n,m,initial);
    setBorderAndF(x0,f, n,m,variant);
    setBorderAndF(x1,f,n,m,variant);


    double maxFourth=-1.0, max4thX, max4thY;
    double maxFourthMult=-1.0, max4thXMult, max4thYMult;
    int counter=0;
    bool t;
    Pair residual;
    Pair r0;
    double eps = ui->lineEdit->text().toDouble(&t);
    int maxCounter = ui->spinBox_4->value();
    double currentEps=-1.0;
    QProgressDialog progress("Computing main task...", "Abort", 0, maxCounter, this);
    progress.setMinimumDuration(1000);
    progress.setWindowModality(Qt::WindowModal);


    r0=countResidual(x0,f,n,m);


    double lambdaMin = 4/(h*h) * sin(M_PI*h/(2.0)) * sin(M_PI*h/(2.0)) + 4/(k*k) * sin(M_PI*k/(2.0)) * sin(M_PI*k/(2.0));
    double first = -1;
    double second = h*h/12.0 + k*k/12.0;
    second/=2.0; //Because of  (b-a)=(d-c)=2
    if (isMagic)
        second/=4.0; //Magic for similarity real and estimate
    double fourthEst = ui->lineEdit_2->text().toDouble(&t);
    double r = r0.maxRes;
    if (ui->checkBox_3->isChecked())
        r = r0.euclRes;

    if (maxCounter>0)
    do
    {
        progress.setValue(counter);

        QString progressMsg = "Computing main task...";
        progressMsg += QString("\nWas done %1 iterations").arg(counter);
        progressMsg += QString("\nMax 4th derivative %1").arg(maxFourth);
        progressMsg += QString("\nMax 4th derivative (multiplier) %1").arg(maxFourthMult);
        progressMsg += QString("\nAccuracy %1").arg(QString::number(currentEps, 'e', 5));
        progressMsg += QString("\nResidual %1 (Op %2)").arg(residual.maxRes).arg(residual.maxResOp);
        progressMsg += QString("\nEuclidian residual %1 ").arg(residual.euclRes);

        first = pow(cos(M_PI/n),counter)/lambdaMin;
        progressMsg += QString("\nComputed est. %1 + %2 = %3").arg(QString::number(first*r)).arg(QString::number(second*fourthEst)).arg(QString::number(first*r+second*fourthEst));

        progress.setLabelText(progressMsg);

        QCoreApplication::processEvents();
        if (progress.wasCanceled())
            break;
        residual = computeNext(x0,x1,f,n,m,type);
        double ** tmp = x0;
        x0=x1;
        x1=tmp;
        counter++;
        currentEps = normRazn(x0,x1,n,m);
        maxFourth = maxFourthDerivative(x0,n,m,max4thX,max4thY,1);
        maxFourthMult = maxFourthDerivative(x0,n,m,max4thXMult,max4thYMult);
    } while (currentEps>eps && counter < maxCounter);
     progress.setValue(maxCounter);

     for (int i=0; i<n+1; i++)
     {
         delete[] x1[i];
         delete[] f[i];
     }
     delete[] x1;
     delete[] f;


    //-------------------
    int n2=2*n;
    int m2=2*m;        
    Pair residual2;
    double maxX, maxY, max1,max2=-1.0, maxX2=-1.0, maxY2=-1.0;
    double maxDiff=-1;
    int maxI=-1, maxJ=-1;

    double** x02=NULL, **x12=NULL;
    if (n2*m2<=7000*7000)
    {
        x02 = new double*[n2+1];
        x12 = new double*[n2+1];
        double** f2 = new double*[n2+1];
        for (int i=0; i<n2+1; i++)
        {
            x02[i] = new double[m2+1];
            x12[i] = new double[m2+1];
            f2[i] = new double[m2+1];
        }
        setBorderAndF(x02,f2,n2,m2,variant);
        setBorderAndF(x12,f2,n2,m2,variant);
        setInitial(x02,n2,m2,initial);
        setInitial(x12,n2,m2,initial);
        setBorderAndF(x02,f2,n2,m2,variant);
        setBorderAndF(x12,f2,n2,m2,variant);

        int counter2=0;
        maxFourth=-1.0;
        double currentEps2=-1.0;
        QProgressDialog progress2("Computing doubled task...", "Abort", 0, maxCounter, this);
        progress2.setMinimumDuration(0);
        progress2.setWindowModality(Qt::WindowModal);
        if (maxCounter>0)
            do
        {
            progress2.setValue(counter2);

            QString progressMsg = "Computing doubled task...";
            progressMsg += QString("\nWas done %1 iterations").arg(counter2);
            progressMsg += QString("\nMax 4th derivative %1").arg(maxFourth);
            progressMsg += QString("\nAccuracy %1").arg(QString::number(currentEps2, 'e', 5));
            progressMsg += QString("\nResidual %1 (Op %2)").arg(residual2.maxRes).arg(residual2.maxResOp);
            progressMsg += QString("\nEuclidian residual %1 ").arg(residual2.euclRes);
            progress2.setLabelText(progressMsg);

            QCoreApplication::processEvents();
            if (progress2.wasCanceled())
                break;
            residual2 = computeNext(x02,x12,f2,n2,m2,type);
            double ** tmp = x02;
            x02=x12;
            x12=tmp;
            counter2++;
            currentEps2 = normRazn(x02,x12,n2,m2);
            maxFourth = maxFourthDerivative(x02,n2,m2,max4thX,max4thY,1);
        } while (currentEps2>eps && counter2 < maxCounter);
        progress2.setValue(maxCounter);


        for (int i=0; i<n2+1; i++)
        {
            delete[] x12[i];
            delete[] f2[i];
        }
        delete[] x12;
        delete[] f2;
        //----------------------


        if (4*n*m<=7000*7000)
            for (int i=1; i<n; i++)
                for (int j=1; j<m; j++)
                {
                    if (fabs(x0[i][j]-x02[i*2][j*2])>maxDiff)
                    {
                        maxDiff = fabs(x0[i][j]-x02[i*2][j*2]);
                        maxI=i;
                        maxJ=j;
                    }
                }
        max2 = maxFourthDerivative(x02,n2,m2,maxX2,maxY2,1);
    }

    max1 = maxFourthDerivative(x0,n,m,maxX,maxY, 1);

    QMessageBox msgBox;
    QString message="";
    message += QString("Was done %1 iterations").arg(counter);
    message += QString("\nAccuracy %1").arg(QString::number(currentEps, 'e', 5));
    message += QString("\n\nMax 4th derivative (main)\t %1 (%2 for x and %3 for y)").arg(max1).arg(maxX).arg(maxY);
    message += QString("\nMax 4th derivative (main with multiplier) %1").arg(maxFourthMult);
    message += QString("\nMax 4th derivative (doubled)\t %1 (%2 for x and %3 for y)").arg(max2).arg(maxX2).arg(maxY2);
    message += QString("\n\nResidual (main)\t %1 (Euclidian %2; Op %3)").arg(residual.maxRes).arg(residual.euclRes).arg(residual.maxResOp);
    message += QString("\nResidual (doubled)\t %1 (Euclidian %2; Op %3)").arg(residual2.maxRes).arg(residual2.euclRes).arg(residual2.maxResOp);
    message += QString("\nr0 (main): %1 (Euclidian %2)\n").arg(r0.maxRes).arg(r0.euclRes);
    msgBox.setText(message);
    msgBox.exec();

    ui->label_8->setText(QString("Max diff |v2-v| = %1").arg(maxDiff));
    ui->label_9->setText(QString("In (i,j)=(%1,%2)=(%3,%4)").arg(maxI).arg(maxJ).arg(a+maxI*h).arg(c+maxJ*k));

    ui->label_12->setText(message);

    updateEstimate();

//    double lambdaMin = 4/(h*h) * sin(M_PI*h/(2.0)) * sin(M_PI*h/(2.0)) + 4/(k*k) * sin(M_PI*k/(2.0)) * sin(M_PI*k/(2.0));
//    double second = h*h/12.0 + k*k/12.0;
//    second/=2.0; //Because of  (b-a)=(d-c)=2
//    if (isMagic)
//        second/=4.0; //Magic for similarity real and estimate
//    double fourthEst = ui->lineEdit_2->text().toDouble(&t);
//    double r = r0.maxRes;
//    if (ui->checkBox_3->isChecked())
//        r = r0.euclRes;
    first = pow(cos(M_PI/n),maxCounter)/lambdaMin;
    ui->label_7->setText(QString("Computed est. %1 + %2 = %3").arg(QString::number(first*r)).arg(QString::number(second*fourthEst)).arg(QString::number(first*r+second*fourthEst)));


    if (ui->checkBox->checkState() == Qt::Checked && n*m<3000)
    {
        table->setColumnCount(n+1);
        table->setRowCount(m+1);
        table->setWindowTitle("Main task");
        QStringList headers;
        for (int i=0; i<n+1; i++)
            headers.append(QString::number(a+i*h));
        table->setHorizontalHeaderLabels(headers);
        QStringList vheaders;
        for (int j=m; j>=0; j--)
            vheaders.append(QString::number(c+j*k));
        table->setVerticalHeaderLabels(vheaders);
        //table->setColumnWidth(0,35);

        for (int i=0; i<n+1; i++)
            for (int j=0; j<m+1; j++)
            {
                table->setItem(m-j,i,new QTableWidgetItem(QString::number(x0[i][j],'g',3)));
            }
        table->show();

        if (n2*m2<=7000*7000)
        {
            splineTable->setColumnCount(n+1);
            splineTable->setRowCount(m+1);
            splineTable->setWindowTitle("Main task diff");
            splineTable->setHorizontalHeaderLabels(headers);
            splineTable->setVerticalHeaderLabels(vheaders);
            for (int i=0; i<n+1; i++)
                for (int j=0; j<m+1; j++)
                {
                    splineTable->setItem(m-j,i,new QTableWidgetItem(QString::number(fabs(x0[i][j]-x02[i*2][j*2]))));
                }
            splineTable->show();
        }
    }

    for (int i=0; i<n+1; i++)
    {
        delete[] x0[i];
    }
    if (x02)
        for (int i=0; i<n2+1; i++)
        {
            delete[] x02[i];
        }
    delete[] x0;
    delete[] x02;

}

void MainWindow::updateEstimate()
{
    double n = ui->spinBox_2->value();
    double m = ui->spinBox_3->value();
    double h = 2.0/n;
    double k = 2.0/m;
    double lambdaMin = 4/(h*h) * sin(M_PI*h/(2.0)) * sin(M_PI*h/(2.0)) + 4/(k*k) * sin(M_PI*k/(2.0)) * sin(M_PI*k/(2.0));
    double maxCounter = ui->spinBox_4->value();
    double first = pow(cos(M_PI/n),maxCounter)/lambdaMin;
    //double second = 1.0/(n*n*12.0) + 1.0/(m*m*12.0);
    double second = h*h/12.0 + k*k/12.0;
    second/=2.0;
    if (isMagic)
        second/=4.0; //Magic for similarity real and estimate

    ui->label_13->setText(QString("Est. %1 ||r0|| + %2 *f^4").arg(QString::number(first)).arg(QString::number(second)));
}

void MainWindow::on_pushButton_4_clicked()
{
    //Test task
    const int n = ui->spinBox_2->value();
    const int m = ui->spinBox_3->value();
    const double h = 2.0/n;
    const double k = 2.0/m;
    const double a=-1,c=-1;
    //double b=1, d=1;
    int initial = -1;
    if (ui->radioButton->isChecked())
        initial = 0;
    else if (ui->radioButton_2->isChecked())
        initial = 1;
    else if (ui->radioButton_5->isChecked())
        initial = 2;
    int type = ui->radioButton_3->isChecked() ? 0 : 1;

    double ** tmp;
    double** x0, **x1;
    x0 = new double*[n+1];
    x1 = new double*[n+1];
    double** f = new double*[n+1];
    for (int i=0; i<n+1; i++)
    {
        x0[i] = new double[m+1];
        x1[i] = new double[m+1];
        f[i] = new double[m+1];
    }
    setBorderAndF(x0,f, n,m,-1);
    setBorderAndF(x1,f,n,m,-1);
    setInitial(x0,n,m,initial);
    setInitial(x1,n,m,initial);
    setBorderAndF(x0,f, n,m,-1);
    setBorderAndF(x1,f,n,m,-1);

    double maxFourth=-1.0, max4thX, max4thY;
    double maxFourthMult=-1.0, max4thXMult, max4thYMult;
    int counter=0;
    bool t;
    double eps = ui->lineEdit->text().toDouble(&t);
    int maxCounter = ui->spinBox_4->value();
    Pair residual, r0;
    double currentEps=-1.0;
    QProgressDialog progress("Computing test task...", "Abort", 0, maxCounter, this);
    progress.setMinimumDuration(1000);
    progress.setWindowModality(Qt::WindowModal);

    r0=countResidual(x0,f,n,m);

    double first=-1;
    double second = h*h/12.0 + k*k/12.0;
    second/=2.0; //Because of  (b-a)=(d-c)=2
    if (isMagic)
        second/=4.0; //Magic for similarity real and estimate
    double lambdaMin = 4/(h*h) * sin(M_PI*h/(2.0)) * sin(M_PI*h/(2.0)) + 4/(k*k) * sin(M_PI*k/(2.0)) * sin(M_PI*k/(2.0));
    double fourthEst = ui->lineEdit_2->text().toDouble(&t);
    double r = r0.maxRes;
    if (ui->checkBox_3->isChecked())
        r = r0.euclRes;

    if (maxCounter>0)
    do
    {
        progress.setValue(counter);
        QString progressMsg = "Computing test task...";
        progressMsg += QString("\nWas done %1 iterations").arg(counter);
        progressMsg += QString("\nMax 4th derivative %1").arg(maxFourth);
        progressMsg += QString("\nMax 4th derivative with multiplier %1").arg(maxFourthMult);
        progressMsg += QString("\nAccuracy %1").arg(QString::number(currentEps, 'e', 5));
        progressMsg += QString("\nResidual %1 (Op %2)").arg(residual.maxRes).arg(residual.maxResOp);
        progressMsg += QString("\nEuclidian residual %1 ").arg(residual.euclRes);
        progressMsg += QString("\nDiff in (0,0) %1 ").arg(fabs(u(a+n/2*h,c+m/2*k)-x0[n/2][m/2]));

        first = pow(cos(M_PI/n),counter)/lambdaMin;
        progressMsg += QString("\nComputed est. %1 + %2 = %3").arg(QString::number(first*r)).arg(QString::number(second*fourthEst)).arg(QString::number(first*r+second*fourthEst));

        QCoreApplication::processEvents();
        progress.setLabelText(progressMsg);
        if (progress.wasCanceled())
            break;
        residual = computeNext(x0,x1,f,n,m,type);

        tmp = x0;
        x0=x1;
        x1=tmp;

        counter++;
        currentEps = normRazn(x0,x1,n,m);        
        maxFourth = maxFourthDerivative(x0,n,m,max4thX,max4thY,1);
        maxFourthMult = maxFourthDerivative(x0,n,m,max4thXMult,max4thYMult);
    } while (currentEps>eps && counter < maxCounter);
     progress.setValue(maxCounter);

    double maxDiff = -1;
    int maxI=-1, maxJ=-1;
    for (int i=0; i<n+1; i++)
        for (int j=0; j<m+1; j++)
        {
            if (fabs(u(a+i*h,c+j*k)-x0[i][j])>maxDiff)
            {
                maxDiff = fabs(u(a+i*h,c+j*k)-x0[i][j]);
                maxI=i;
                maxJ=j;
            }
        }

    double maxX, maxY, max1;
    max1 = maxFourthDerivative(x0,n,m,maxX,maxY,1);
    maxFourthMult = maxFourthDerivative(x0,n,m,max4thXMult,max4thYMult);

    QMessageBox msgBox;
    QString message="";
    message += QString("Was done %1 iterations").arg(counter);
    message += QString("\nAccuracy %1").arg(QString::number(currentEps, 'e', 5));
    message += QString("\n\nMax 4th derivative (test)\t %1 (%2 for x and %3 for y)").arg(max1).arg(maxX).arg(maxY);
    message += QString("\nMax 4th derivative (test with multiplier)\t %1 (%2 for x and %3 for y)").arg(maxFourthMult).arg(max4thXMult).arg(max4thYMult);
    message += QString("\n\nResidual (test)\t %1 (Euclidian %2; Op %3)").arg(residual.maxRes).arg(residual.euclRes).arg(residual.maxResOp);
    message += QString("\nr0 (test): %1 (Euclidian %2)\n").arg(r0.maxRes).arg(r0.euclRes);
    msgBox.setText(message);
    msgBox.exec();

    ui->label_8->setText(QString("Max diff |u-v| = %1").arg(QString::number(maxDiff, 'e', 5)));
    ui->label_9->setText(QString("In (i,j)=(%1,%2)=(%3,%4)").arg(maxI).arg(maxJ).arg(a+maxI*h).arg(c+maxJ*k));

    ui->label_12->setText(message);

    updateEstimate();
//    double lambdaMin = 4/(h*h) * sin(M_PI*h/(2.0)) * sin(M_PI*h/(2.0)) + 4/(k*k) * sin(M_PI*k/(2.0)) * sin(M_PI*k/(2.0));
//    double second = h*h/12.0 + k*k/12.0;
//    second/=2.0; //Because of  (b-a)=(d-c)=2
//    if (isMagic)
//        second/=4.0; //Magic for similarity real and estimate
//    double fourthEst = ui->lineEdit_2->text().toDouble(&t);
//    //double fourthEst = 19*4*M_E;//ui->lineEdit_2->text().toDouble(&t);
//    double r = r0.maxRes;
//    if (ui->checkBox_3->isChecked())
//        r = r0.euclRes;
    first = pow(cos(M_PI/n),maxCounter)/lambdaMin; //See declarations above
    ui->label_7->setText(QString("Computed est. %1 + %2 = %3").arg(QString::number(first*r)).arg(QString::number(second*fourthEst)).arg(QString::number(first*r+second*fourthEst)));

    if (ui->checkBox->checkState() == Qt::Checked)
    {
        table->setColumnCount(n+1);
        table->setRowCount(m+1);
        table->setWindowTitle("Test task");
        QStringList headers;
        for (int i=0; i<n+1; i++)
            headers.append(QString::number(a+i*h));
        table->setHorizontalHeaderLabels(headers);
        QStringList vheaders;
        for (int j=m; j>=0; j--)
            vheaders.append(QString::number(c+j*k));
        table->setVerticalHeaderLabels(vheaders);
        //table->verticalHeader()->hide();
        //table->setColumnWidth(0,35);


        for (int i=0; i<n+1; i++)
            for (int j=0; j<m+1; j++)
            {
                table->setItem(m-j,i,new QTableWidgetItem(QString::number(x0[i][j],'g',4)));
            }
        table->show();

        splineTable->setColumnCount(n+1);
        splineTable->setRowCount(m+1);
        splineTable->setWindowTitle("Test task diff");
        splineTable->setHorizontalHeaderLabels(headers);
        splineTable->setVerticalHeaderLabels(vheaders);
        for (int i=0; i<n+1; i++)
            for (int j=0; j<m+1; j++)
            {
                splineTable->setItem(m-j,i,new QTableWidgetItem(QString::number(fabs(x0[i][j]-u(a+i*h,c+j*k)))));
            }
        splineTable->show();
    }    

    for (int i=0; i<n+1; i++)
    {
        delete[] x0[i];
        delete[] x1[i];
        delete[] f[i];
    }
    delete[] x1;
    delete[] x0;
    delete[] f;
}

void MainWindow::changeMagicBehavior()
{
    isMagic = !isMagic;
    if (isMagic)
        ui->pushButton_3->setText("Main task.");
    else
        ui->pushButton_3->setText("Main task");
}

